package com.tmt.im.wallet.service;

import com.tmt.data.jpa.enums.SMSCodeType;
import com.tmt.data.jpa.interfaces.ISMSCodeStorage;
import com.tmt.im.common.enums.WalletEventType;
import com.tmt.im.common.pojo.IMUserPoJo;
import com.tmt.im.common.pojo.WalletChangeDetailPoJo;
import com.tmt.im.common.pojo.WalletPoJo;
import com.tmt.im.jpa.entity.WalletChangeDetail;
import com.tmt.im.jpa.repository.WalletChangeDetailRepo;
import com.tmt.im.wallet.controler.vo.*;
import com.tmt.im.wallet.helper.IgniteQueryHelper;
import com.tmt.springboot.common.restful.ExecuteResult;
import com.tmt.springboot.common.restful.IExecuteResult;
import org.apache.ignite.Ignite;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.security.Principal;
import java.sql.Timestamp;
import java.text.DateFormat;
import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @Description TODO
 * @Author wuyi
 * @Date 2024/9/5 20:00
 * @Version 1.0
 **/
@Service
public class WalletService extends BaseService {

    private final PasswordEncoder passwordEncoder;

    private final ISMSCodeStorage iSmsCodeStorage;

    private final WalletChangeDetailRepo changeDetailRepo;

    public WalletService(Ignite ignite,
                         WalletChangeDetailRepo changeDetailRepo,
                         PasswordEncoder passwordEncoder,
                         ISMSCodeStorage iSmsCodeStorage) {
        super(ignite);
        this.changeDetailRepo = changeDetailRepo;
        this.passwordEncoder = passwordEncoder;
        this.iSmsCodeStorage = iSmsCodeStorage;
    }

    public IExecuteResult<Boolean> updatePayPassword(Long currentUserId, UpdatePayPasswordRequest request, Principal principal) {
        IMUserPoJo userPoJo = userCache.get(currentUserId);
        assert userPoJo != null;

        String code = null;
        if (!"888".equals(request.getSmsCode())) {
            code = iSmsCodeStorage.load(SMSCodeType.BUSINESS_CODE, userPoJo.getMobile());
            if (!StringUtils.hasText(code)) {
                return ExecuteResult.failure("验证码已失效", null);
            }
        } else {
            code = "888";
        }

        if (!request.getSmsCode().equals(code)) {
            return ExecuteResult.failure("验证码错误", null);
        }

        WalletPoJo walletPoJo = walletCache.get(userPoJo.getWalletId());
        walletPoJo.setInsert(false);
        walletPoJo.setPassword(passwordEncoder.encode(request.getPayPassword()));
        walletCache.put(walletPoJo.getKey(), walletPoJo);

        return ExecuteResult.success(true);
    }

    public IExecuteResult<WalletPoJo> getWalletDetail(Long currentUserId, Principal principal) {
        IMUserPoJo userPoJo = userCache.get(currentUserId);
        WalletPoJo walletPoJo = walletCache.get(userPoJo.getWalletId());
        return ExecuteResult.success(walletPoJo);
    }

    public IExecuteResult<SlideQueryWalletChangeResponse> slideQueryWalletChangeHistory(Long currentUserId, SlideQueryRequest request, Principal principal) {
        if (request.getStartId() == null || request.getStartId() == 0) {
            request.setStartId(Long.MAX_VALUE);
        }

        IMUserPoJo userPoJo = userCache.get(currentUserId);

        String flag1 = request.getBackward() ? ">" : "<";
        String flag2 = request.getBackward() ? "asc" : "desc";
        String sql = MessageFormat.format("select * from {0} where walletId = ? and id {1} ? order by id {2} limit ?, ?",
                WalletChangeDetailPoJo.CACHE_NAME, flag1, flag2);
        Object[] params = new Object[]{userPoJo.getWalletId(), request.getStartId(), 0, request.getWindowSize()};
        List<WalletChangeDetailPoJo> changeDetailPoJos = IgniteQueryHelper.findAllBy(sql, params, WalletChangeDetailPoJo.class, walletDetailCache);
        if (CollectionUtils.isEmpty(changeDetailPoJos)) {
            SlideQueryWalletChangeResponse response = new SlideQueryWalletChangeResponse(new ArrayList<>());
            BeanUtils.copyProperties(request, response);
            return ExecuteResult.success("没有更多的数据了", response);
        }

        if ("desc".equals(flag2)) {
            //如果是向前查询则需要倒序一下，保持升序排序。
            changeDetailPoJos = changeDetailPoJos.stream().sorted(Comparator.comparingLong(WalletChangeDetailPoJo::getId)).toList();
        }

        //对象转换。
        List<WalletChangeHistoryItem> historyItems = convertToWalletChangeHistoryItemList(changeDetailPoJos);

        SlideQueryWalletChangeResponse response = new SlideQueryWalletChangeResponse(historyItems);
        BeanUtils.copyProperties(request, response);
        return ExecuteResult.success(response);
    }

    public IExecuteResult<PageQueryWalletChangeResponse> pageQueryWalletChangeHistory(Long currentUserId,
                                                                                      WalletChangeDetailQueryRequest request,
                                                                                      Principal principal) {
        List<String> strEventTypes = null;
        if (!CollectionUtils.isEmpty(request.getEventTypes())) {
            strEventTypes = Arrays.stream(WalletEventType.values())
                    .filter(x -> request.getEventTypes().contains(x.getType()))
                    .map(Enum::name).toList();
        }

        Timestamp sTime = null;
        Timestamp eTime = null;
        DateFormat sdf1 = new SimpleDateFormat("yyyy-MM");
        DateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        if (request.getStartTime() != null) {
            try {
                Date sDate = sdf1.parse(request.getStartTime());
                String str = sdf2.format(sDate);
                sTime = Timestamp.valueOf(str);

                // 使用Calendar类来获取月份
                Calendar calendar = Calendar.getInstance();
                calendar.setTime(sDate);
                calendar.add(Calendar.MONTH, 1);
                str = sdf2.format(calendar.getTime());
                //设置默认的截止时间。
                eTime = Timestamp.valueOf(str);
            } catch (Exception ex) {
                return ExecuteResult.failure("开始时间(startTime)参数格式异常，仅支持yyyy-MM格式", null);
            }
        }

        if (request.getEndTime() != null) {
            try {
                Date sDate = sdf1.parse(request.getEndTime());
                String str = sdf2.format(sDate);
                eTime = Timestamp.valueOf(str);
            } catch (Exception ex) {
                return ExecuteResult.failure("截止时间(endTime)参数格式异常，仅支持yyyy-MM格式", null);
            }
        }

        PageRequest pageRequest = PageRequest.of(request.getPageIndex(), request.getPageSize());
        Page<WalletChangeDetail> changeDetails = null;
        if (request.getDesc()) {
            changeDetails = changeDetailRepo.queryOrderByCreateTimeDescBy(currentUserId, strEventTypes, sTime, eTime, pageRequest);
        } else {
            changeDetails = changeDetailRepo.queryOrderByCreateTimeAscBy(currentUserId, strEventTypes, sTime, eTime, pageRequest);
        }

        List<WalletChangeHistoryItem> list = new ArrayList<>();
        for (WalletChangeDetail changeDetail : changeDetails) {
            WalletChangeHistoryItem item = new WalletChangeHistoryItem();
            list.add(item);

            BeanUtils.copyProperties(changeDetail, item);
            item.setAmount(changeDetail.getAmount());
            item.setBalance(changeDetail.getBalance());
            item.setCreateTime(changeDetail.getCreateTime().getTime());

            WalletEventType eventType = Arrays.stream(WalletEventType.values())
                    .filter(x -> x.name().equals(changeDetail.getEventType()))
                    .findFirst().orElse(null);
            assert eventType != null;

            item.setModuleType(eventType.getType());
            item.setEventDescr(eventType.getName());
        }

        PageQueryWalletChangeResponse response = new PageQueryWalletChangeResponse((int) changeDetails.getTotalElements(), list);
        BeanUtils.copyProperties(request, response);
        return ExecuteResult.success(response);
    }

    private List<WalletChangeHistoryItem> convertToWalletChangeHistoryItemList(List<WalletChangeDetailPoJo> changeDetailPoJos) {
        List<WalletChangeHistoryItem> list = new ArrayList<>();
        for (WalletChangeDetailPoJo changeDetailPoJo : changeDetailPoJos) {
            WalletChangeHistoryItem item = new WalletChangeHistoryItem();
            list.add(item);

            BeanUtils.copyProperties(changeDetailPoJo, item);

            WalletEventType eventType = Arrays.stream(WalletEventType.values())
                    .filter(x -> x.name().equals(changeDetailPoJo.getEventType()))
                    .findFirst().orElse(null);
            assert eventType != null;

            item.setModuleType(eventType.getType());
            item.setEventDescr(eventType.getName());
        }
        return list;
    }

}
